// fast4j - Fast & Agile Service Tools for Java
// Copyright (C) 2007 Alexandre ROMAN
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

// $Id: ServiceBridgeInterceptor.java 36 2007-03-27 22:02:40Z alexandre.roman $

package client;

import java.net.InetAddress;
import java.net.UnknownHostException;

import org.aspectj.lang.ProceedingJoinPoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import service.api.ServiceContext;
import fast4j.ejbbridge.ServiceBridge;
import fast4j.ejbbridge.ServiceCall;
import fast4j.ejbbridge.ServiceInvocationFailedException;
import fast4j.ejbbridge.ServiceResult;

/**
 * {@link ServiceBridge} interceptor. This class is responsible for creating a
 * new {@link ServiceContext} before each service call, and for logging result
 * after the service returned.
 * @author alexandre.roman
 */
public class ServiceBridgeInterceptor {
    private final Logger log = LoggerFactory.getLogger(getClass());
    
    @SuppressWarnings("unchecked")
    public Object intercept(ProceedingJoinPoint jp) throws Throwable {
        // create a new instance
        // (in a real example, this instance would get instancied by some
        // servlet filter, getting values from user session)
        final ServiceContext ctx = new ServiceContext();
        ctx.setInvocationTimestamp(System.currentTimeMillis());
        
        String clientHost = null;
        try {
            clientHost = InetAddress.getLocalHost().getHostName();
        } catch (UnknownHostException e) {
            clientHost = "localhost";
        }
        ctx.setClientHost(clientHost);
        
        // get the first argument (of type ServiceCall)
        final ServiceCall call = (ServiceCall) jp.getArgs()[0];
        final String serviceContextKey = "serviceContext";
        // add our ServiceContext
        call.getContext().put(serviceContextKey, ctx);
        log.debug("ServiceContext before invocation: {}", ctx);
        
        final ServiceResult result;
        ServiceContext resultCtx = null;
        try {
            // call method
            result = (ServiceResult) jp.proceed();
            resultCtx = (ServiceContext) result.getContext().get(
                serviceContextKey);
        } catch (ServiceInvocationFailedException e) {
            resultCtx = (ServiceContext) e.getServiceCall().getContext().get(
                serviceContextKey);
            throw e.getCause();
        } finally {
            // if the ServiceContext was updated by the service method,
            // changes get printed here
            log.debug("ServiceContext after invocation: {}", resultCtx);
        }
        
        // in a real example, we may really use data from the ServiceContext,
        // such as error messages
        
        return result;
    }
}
